package com.ebs.md.api.abs;

/**
 * Perforce Revision:
 *  $File: //depot/MarketData/commons-md-api/MAIN/src/main/java/com/ebs/md/api/abs/AbstractAggrOrderBook.java $
 *  $Revision: #2 $  $Change: 114409 $  $DateTime: 2012/09/02 09:29:07 $  $Author: Arik.Sher $
 */

import java.util.Comparator;
import java.util.List;
import java.util.NavigableSet;
import java.util.SortedMap;

import com.ebs.md.api.BookSide;
import com.ebs.md.api.IAggregatedByPriceBookEntry;
import com.ebs.md.api.IBookEntry;
import com.ebs.md.api.IIdentifiedOrder;
import com.ebs.md.api.IOrder;
import com.ebs.md.api.IProduct;
import com.ebs.md.api.Rate;
import com.ebs.md.api.comparators.BasicBookEntryComparator;


public abstract class AbstractAggrOrderBook 
extends AbstractOrderBook<IAggregatedByPriceBookEntry, IIdentifiedOrder>
{
	protected final static Comparator<IAggregatedByPriceBookEntry> bookEntryComparator = new AggregCompr(); 

	
	protected AbstractAggrOrderBook(IProduct proudct)
	{
		super(proudct);
	}
	
	protected AbstractAggrOrderBook(IProduct proudct, List<IAggregatedByPriceBookEntry> bids, List<IAggregatedByPriceBookEntry> offers)
	{
		super(proudct, bids, offers);
	}

	protected IAggregatedByPriceBookEntry createBookEntry(IOrder order) {
		BookSide bookSide = BookSide.fromOrderSide(order.getSide());
		
		return new BasicBookEntry(bookSide, order.getRate(), order.getAmount());
	}
	
	
	protected Comparator<IAggregatedByPriceBookEntry> getBookEntryComparator() {
		return bookEntryComparator;
	}

	protected IAggregatedByPriceBookEntry focusOnFirstOnly(SortedMap<Rate, NavigableSet<IAggregatedByPriceBookEntry>> map, Rate rate) {
		NavigableSet<IAggregatedByPriceBookEntry> listWithSizeof1 = map.get(rate);
		IAggregatedByPriceBookEntry be = null;
		if ( listWithSizeof1 != null ) {
			be = listWithSizeof1.iterator().next();
		}
		return be;
	}

	protected void doAdd(IIdentifiedOrder order) {
		SortedMap<Rate, NavigableSet<IAggregatedByPriceBookEntry>> map = getAffectedOBSide(order.getSide());
		IAggregatedByPriceBookEntry be = focusOnFirstOnly(map, order.getRate());
		
		if ( be != null ) {
			be.increaseAmount(order.getAmount());
		} else {
			be = createBookEntry(order);
			beforeNewBookEntry(be, order);
			map.put(order.getRate(), createBookEntriesAtRate(be));
		}
	}
	
	
	protected void doDecrease(IIdentifiedOrder order) {
		SortedMap<Rate, NavigableSet<IAggregatedByPriceBookEntry>> map = getAffectedOBSide(order.getSide());
		IAggregatedByPriceBookEntry be = focusOnFirstOnly(map, order.getRate());
		
		if ( be != null ) {
			boolean priceStillActive = be.decreaseAmount(order.getAmount());
			
			if ( !priceStillActive ) {
				beforeRemovingBookEntry(be, order);
				map.remove(be.getRate());
			}
		} else {
			//TODO: log
		}
		
	}

	protected void handleAddition(IIdentifiedOrder order) {
		doAdd(order);
	}

	protected void handleRemoval(IIdentifiedOrder order) {
		doDecrease(order);
	}

	protected void handleAmountIncrease(IIdentifiedOrder order) {
		doAdd(order);
	}

	protected void handleAmountDecrease(IIdentifiedOrder order) {
		doDecrease(order);
	}
	
	protected void postFullSnapshot() {
		// do nothing
	}

	/**
	 * 
	 * @param newBookEntry - the BookEntry before it is entered into the Book.
	 * @param order        - the Order which affects it.
	 */
	abstract void beforeNewBookEntry(IAggregatedByPriceBookEntry newBookEntry, IIdentifiedOrder order);
	
	/**
	 * 
	 * @param bookEntry - BookEntry before removed...
	 * @param order     - the Order which affects it.
	 */
	abstract void beforeRemovingBookEntry(IAggregatedByPriceBookEntry bookEntry, IIdentifiedOrder order);
	
	
	static class AggregCompr 
	implements Comparator<IAggregatedByPriceBookEntry> 
	{
		final static private Comparator<IBookEntry> compr =  new BasicBookEntryComparator();

		public int compare(IAggregatedByPriceBookEntry o1, IAggregatedByPriceBookEntry o2) {
			return compr.compare(o1, o2);
		}

	}

}
